package vis;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JPanel;

import logic.PlayfairCipher;

public class KeyPanel extends JPanel {
	private static final long serialVersionUID = -4427004168382367571L;
	private PlayfairCipher cipher = null;
	private Font font = new Font(Font.MONOSPACED, Font.BOLD, 36);
	private int mode[][] = new int[5][5];
	private int x1, y1, x2, y2, x3, y3, x4, y4;
	private int hmode = 0;
	private int phase = 0;
	private String s1, s2, grayText;
	private boolean keyOnly = true;
	
	public KeyPanel(PlayfairCipher cipher, boolean keyOnly)
	{
		super();
		this.cipher = cipher;
		this.keyOnly = keyOnly;
		if(keyOnly)
		{
			this.setMinimumSize(new Dimension(251, 251));
			this.setMaximumSize(new Dimension(251, 251));
			this.setPreferredSize(new Dimension(251, 251));
		}
		else
		{
			this.setMinimumSize(new Dimension(1000, 251));
			this.setMaximumSize(new Dimension(1000, 251));
			this.setPreferredSize(new Dimension(1000, 251));
		}
		resetStrings();
		phase = -1;
	}
	
	public void paintComponent(Graphics gg)
	{
		Graphics2D g = (Graphics2D)gg;
		g.clearRect(0, 0, getWidth(), getHeight());
		g.setColor(Color.BLACK);
		
		for(int x = 0; x <= 5; ++x)
			g.drawLine(x * 50, 0, x * 50, 250);
		for(int y = 0; y <= 5; ++y)
			g.drawLine(0, y * 50, 250, y * 50);	
		
		g.clipRect(1, 1, 249, 249);
		g.setFont(font);
		
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		if(hmode == 1)
		{
			g.setColor(new Color(0, 255, 255, 64));
			boolean flipx = x2 < x1;
			boolean flipy = y2 < y1;
			
			if(flipx) { int tmp = x1; x1 = x2; x2 = tmp; }
			if(flipy) { int tmp = y1; y1 = y2; y2 = tmp; }
			//System.out.println(x1 + " " + y1 + " " + x2 + " " + y2);
			g.fillRect(x1 * 50, y1 * 50, (x2-x1+1) * 50, (y2-y1+1) * 50);
			if(flipx) { int tmp = x1; x1 = x2; x2 = tmp; }
			if(flipy) { int tmp = y1; y1 = y2; y2 = tmp; }
			
			g.setColor(new Color(255, 255, 0, 192));
			g.setStroke(new BasicStroke(40.0f, BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND, 0.0f));
			if(phase == 0)
				g.drawLine(x1 * 50 + 25, y1 * 50 + 25, x2 * 50 + 25, y1 * 50 + 25);
			else if(phase == 1)
				g.drawLine(x2 * 50 + 25, y2 * 50 + 25, x1 * 50 + 25, y2 * 50 + 25);
		}
		else if(hmode == 2)
		{
			g.setColor(new Color(255, 255, 0, 192));
			g.setStroke(new BasicStroke(40.0f, BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND, 0.0f));
			if(phase == 0)
			{
				g.drawLine(x1 * 50 + 25, y1 * 50 + 25, x1 * 50 + 25, (y1 + 1) * 50 + 25);
				if(y3 < y1) g.drawLine(x1 * 50 + 25, -25, x1 * 50 + 25, 25);
			}
			else if(phase == 1)
			{
				g.drawLine(x2 * 50 + 25, y2 * 50 + 25, x2 * 50 + 25, (y2 + 1) * 50 + 25);
				if(y4 < y2) g.drawLine(x1 * 50 + 25, -25, x1 * 50 + 25, 25);
			}
		}
		else if(hmode == 3)
		{
			g.setColor(new Color(255, 255, 0, 192));
			g.setStroke(new BasicStroke(40.0f, BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND, 0.0f));
			if(phase == 0)
			{
				g.drawLine(x1 * 50 + 25, y1 * 50 + 25, (x1 + 1) * 50 + 25, y1 * 50 + 25);
				if(x3 < x1) g.drawLine(-25, y1 * 50 + 25, 25, y1 * 50 + 25);
			}
			else if(phase == 1)
			{
				g.drawLine(x2 * 50 + 25, y2 * 50 + 25, (x2 + 1) * 50 + 25, y2 * 50 + 25);
				if(x4 < x2) g.drawLine(-25, y1 * 50 + 25, 25, y1 * 50 + 25);
			}
		}
		
		for(int y = 0; y < 5; ++y)
		{
			for(int x = 0; x < 5; ++x)
			{
				switch(mode[x][y])
				{
				default : case 0: g.setColor(Color.BLUE); break;
				case 1: g.setColor(Color.ORANGE); break;
				case 2: g.setColor(Color.GREEN); break;
				}
				if(cipher.getKey() != null)
					g.drawString(cipher.getKey().getLetter(x, y).toUpperCase(), x * 50 + 15, y * 50 + 39);
			}
		}
		
		if(!keyOnly)
		{
			g.setClip(0, 0, getWidth(), getHeight());
			g.setColor(Color.GRAY);
			g.drawString(grayText.toUpperCase(), 315, 50 + 39);
			g.setColor(Color.ORANGE);
			g.drawString(s1.toUpperCase(), 315, 50 + 39);
			g.setColor(Color.GREEN);
			g.drawString(s2.toUpperCase(), 315, 150 + 39);
		}
	}
	
	public void setHighlight(int x1, int y1, int x2, int y2)
	{
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		
		for(int x = 0; x < 5; ++x) for(int y = 0; y < 5; ++y) mode[x][y] = 0;
		
		if(x1 == -1) { hmode = 0; return; }
		
		mode[x1][y1] = mode[x2][y2] = 1;
		mode[x1][y2] = mode[x2][y1] = 2;
		hmode = 1;
		repaint();
	}
	
	public void setVHighlight(int x1, int y1, int x2, int y2, boolean reverse)
	{
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		
		for(int x = 0; x < 5; ++x) for(int y = 0; y < 5; ++y) mode[x][y] = 0;
		
		if(x1 == -1) { hmode = 0; return; }
		
		this.x3 = x1;
		this.y3 = (y1 + 1) % 5;
		
		this.x4 = x2;
		this.y4 = (y2 + 1) % 5;
		
		if(reverse)
		{
			mode[x1][y1] = mode[x2][y2] = 2;
			mode[x3][y3] = mode[x4][y4] = 1;
		}
		else
		{
			mode[x1][y1] = mode[x2][y2] = 1;
			mode[x3][y3] = mode[x4][y4] = 2;
		}
		
		hmode = 2;
		repaint();
	}
	
	public void setHHighlight(int x1, int y1, int x2, int y2, boolean reverse)
	{
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		
		for(int x = 0; x < 5; ++x) for(int y = 0; y < 5; ++y) mode[x][y] = 0;
		
		if(x1 == -1) { hmode = 0; return; }
		
		this.y3 = y1;
		this.x3 = (x1 + 1) % 5;
		
		this.y4 = y2;
		this.x4 = (x2 + 1) % 5;
		
		if(reverse)
		{
			mode[x1][y1] = mode[x2][y2] = 2;
			mode[x3][y3] = mode[x4][y4] = 1;
		}
		else
		{
			mode[x1][y1] = mode[x2][y2] = 1;
			mode[x3][y3] = mode[x4][y4] = 2;
		}
		
		hmode = 3;
		repaint();
	}
	
	public void setPhase(int phase)
	{
		this.phase = phase;
		repaint();
	}
	
	public void resetStrings()
	{
		s1 = "";
		s2 = "";
		grayText = "";
	}
	
	public void appendLetters(String a, String b)
	{
		s1 += a;
		s2 += b;
		repaint();
	}
	
	public void setGrayText(String text)
	{
		grayText = text;
		repaint();
	}
}
